#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindowClass)
{
    ui->setupUi(this);

    _dirFilter = QDir::Files | QDir::NoDotAndDotDot;

    settings = new QSettings("Roger Grayson", "rrenamer32");
    toggleThreads(settings->value("Threads",true).toBool());
    toggleHidden(settings->value("Hidden",true).toBool());
    toggleSystem(settings->value("System",false).toBool());
    ui->chkSaveState->setChecked(settings->value("Savestate",true).toBool());
    toggleOptions(settings->value("Options",false).toBool());
    toggleFind(settings->value("Find",true).toBool());
    this->resize(settings->value("Size",QSize(660,400)).toSize());
    this->move(settings->value("Position").toPoint());

    _activeThreads = 0;

    connect(ui->inFind,SIGNAL(editingFinished()),this,SLOT(resetFind()));
}

MainWindow::~MainWindow()
{
    if(ui->chkSaveState->isChecked())
    {   settings->setValue("Threads",ui->chkThreads->isChecked());
        settings->setValue("Hidden",ui->chkHiddenFiles->isChecked());
        settings->setValue("System",ui->chkSystemFiles->isChecked());
        settings->setValue("Savestate",ui->chkSaveState->isChecked());

        settings->setValue("Options",ui->actionOptions->isChecked());
        settings->setValue("Find",ui->action_Find_and_Replace->isChecked());
        settings->setValue("Size",this->size());
        settings->setValue("Position",this->pos());
    }
    else
    {   settings->clear();
    }

    delete ui;
    delete settings;
}

void MainWindow::on_action_Open_Directory_activated()
{
    dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), ".",
                                            QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
    if(dir==NULL)
           return;
    loadDirectory();
}

void MainWindow::loadDirectory()
{
    QDir directory(dir);
    ui->grpText->setTitle(dir);

    ui->plainTextEdit->clear();
    filesOrig.clear();
    filesNew.clear();

    directory.setFilter(_dirFilter);
    filesOrig = directory.entryList();

    for(int i=0; i<filesOrig.count(); i++)
    {   ui->plainTextEdit->appendPlainText(filesOrig.at(i));
    }
    QString qsTemp = QString("Loaded %1 files").arg(filesOrig.count());
    ui->statusBar->showMessage(qsTemp);
}

void MainWindow::on_action_RRename_activated()
{
    /** if no directory loaded **/
    if(filesOrig.empty())
    {   QMessageBox::critical(this,"ERROR","No directory is loaded",QMessageBox::Ok);
        return;
    }
    /** store new filename list from textedit **/
    {   filesNew.clear();
        filesNew = ui->plainTextEdit->toPlainText().split("\n");
        if(filesNew.count() != filesOrig.count())
        {   QMessageBox::critical(this, "ERROR","Number of output files != number of input files",QMessageBox::Ok);
            return;
        }
    }
    /** rename confirmation **/
    {   QMessageBox::StandardButton reply;
        reply = QMessageBox::question(this,"Confirmation","Are you sure you want to rename all files?",
                                      QMessageBox::Yes | QMessageBox::No);
        if(reply == QMessageBox::No)
            return;
    }
    /** pre-rename duplicate check **/
    {   QStringList::iterator iter;
        for(iter=filesNew.begin(); iter!=filesNew.end(); ++iter)
        {   if(filesNew.count(*iter)>1)
            {   //TODO: expand on this, highlight conflicting names in text edit
                QMessageBox::critical(this,"ERROR","Duplicate file names, cannot rename",QMessageBox::Ok);
                return;
            }
        }
    }
    /** set thread params and launch threads **/
    {   int perThread = filesNew.count()/_threads;
        int extras = filesNew.count()%_threads;
        int offset=0;
        int extra;
        int ops;
        _threadErrors=0;

        renameThreads = new Rename[_threads];

        for(int i=0; i<_threads; i++)
        {
            ops = perThread;
            if(extras)
            {   extras--;extra=1;ops+=extra;
            }
            connect(&(renameThreads[i]),SIGNAL(completed(int)),
                    this,SLOT(renameThreadFinished(int)), Qt::QueuedConnection);

            renameThreads[i].init(&dir,&filesOrig,&filesNew,offset,ops);
            renameThreads[i].start();
            _activeThreads++;
            offset+=ops;
        }
    }
}

void MainWindow::renameThreadFinished(int numErrors)
{
    _threadErrors+=numErrors;
    if( --_activeThreads == 0)
    {   QString qsTemp("Renaming complete.");
        if(_threadErrors)
            qsTemp+= QString("  Error renaming %1 files!").arg(_threadErrors);
        QMessageBox::information(this,"Finished Renaming",qsTemp,QMessageBox::Ok);
        //reload list
        loadDirectory();
    }
}

void MainWindow::on_action_About_activated()
{
    About about(this);
    about.exec();
}

void MainWindow::on_actionE_xit_activated()
{
    QApplication::quit();
}

void MainWindow::on_action_Find_and_Replace_activated()
{
    toggleFind(!ui->grpFind->isVisible());
}

void MainWindow::toggleFind(bool visible)
{
    ui->grpFind->setVisible(visible);
    ui->action_Find_and_Replace->setChecked(visible);
}

void MainWindow::on_actionOptions_activated()
{
    toggleOptions(!ui->grpOptions->isVisible());
}

void MainWindow::toggleOptions(bool visible)
{
    ui->grpOptions->setVisible(visible);
    ui->actionOptions->setChecked(visible);
}


void MainWindow::toggleThreads(bool toggle)
{
    if(toggle)
    {   _threads = QThread::idealThreadCount();
        if(_threads == -1)
        {   _threads = 1;
        }
    }
    else
    {   _threads = 1;
    }
    ui->chkThreads->setChecked(toggle);
}

void MainWindow::toggleHidden(bool toggle)
{   //TODO: optimize
    if(toggle)
        _dirFilter |= QDir::Hidden;
    else
        if(_dirFilter & QDir::Hidden)
            _dirFilter ^= QDir::Hidden;

    ui->chkHiddenFiles->setChecked(toggle);
}

void MainWindow::toggleSystem(bool toggle)
{   //TODO: optimize
    if(toggle)
        _dirFilter |= QDir::System;
    else
        if(_dirFilter & QDir::System)
            _dirFilter ^= QDir::System;

    ui->chkSystemFiles->setChecked(toggle);
}

void MainWindow::on_btnHide_clicked()
{
    on_action_Find_and_Replace_activated();
}

bool MainWindow::findNext()
{
    if(!ui->plainTextEdit->find(ui->inFind->text(),
        (QTextDocument::FindFlag)(ui->chkCaseSensitive->isChecked()?QTextDocument::FindCaseSensitively:0)
        | (QTextDocument::FindFlag)(ui->chkWholeWords->isChecked()?QTextDocument::FindWholeWords:0)
        | (QTextDocument::FindFlag)(ui->chkBackwards->isChecked()?QTextDocument::FindBackward:0) ))
    {   return false;
    }
    ui->plainTextEdit->ensureCursorVisible();
    return true;
}

void MainWindow::resetFind()
{
    ui->plainTextEdit->moveCursor(QTextCursor::Start);
}

bool MainWindow::replace()
{
    if(!ui->plainTextEdit->textCursor().hasSelection())
    {   return false;
    }
    ui->plainTextEdit->textCursor().removeSelectedText();
    ui->plainTextEdit->textCursor().insertText(ui->inReplace->text());
    return true;
}

void MainWindow::on_btnFindNext_clicked()
{
    if(!findNext())
    {   QMessageBox::warning(this,"Not Found","Text string not found!",QMessageBox::Ok);
    }
}

void MainWindow::on_btnReplace_clicked()
{
    if(!replace())
    {   QMessageBox::warning(this,"No selection","Cannot replace text, no text is selected.",QMessageBox::Ok);
        return;
    }
    findNext();
}


void MainWindow::on_btnReplaceAll_clicked()
{
    int count=0;
    resetFind();
    while(findNext())
    {   replace();
        count++;
    }
    QString qsTemp = QString("%1 tokens replaced.").arg(count);
    QMessageBox::information(this,"Finished",qsTemp,QMessageBox::Ok);
}


void MainWindow::on_chkThreads_clicked()
{
    toggleThreads(ui->chkThreads->isChecked());
}

void MainWindow::on_chkHiddenFiles_clicked()
{
    toggleHidden(ui->chkHiddenFiles->isChecked());
}

void MainWindow::on_chkSystemFiles_clicked()
{
    toggleSystem(ui->chkSystemFiles->isChecked());
}

void MainWindow::on_actionReload_activated()
{
    loadDirectory();
}
